[HVM] Fix instruction linear address computation.
authorkfraser@localhost.localdomain <kfraser@localhost.localdomain>
Wed, 22 Nov 2006 10:31:50 +0000 (10:31 +0000)
committerkfraser@localhost.localdomain <kfraser@localhost.localdomain>
Wed, 22 Nov 2006 10:31:50 +0000 (10:31 +0000)
This helps newer isolinux' graphical boot code (which crashes without
this).

Signed-off-by: Jan Beulich <jbeulich@novell.com>
xen/arch/x86/hvm/platform.c
xen/arch/x86/hvm/svm/svm.c
xen/arch/x86/hvm/vmx/vmx.c
xen/include/asm-x86/hvm/hvm.h

index 777f2f3c93f1186163da1916dee7f0a1c09d2b9e..10179c28649b34148e0873538d1a8b0927931362 100644 (file)
@@ -895,9 +895,10 @@ void handle_mmio(unsigned long gpa)
 
     realmode = hvm_realmode(v);
     if ( realmode )
-        inst_addr = (regs->cs << 4) + regs->eip;
+        inst_addr = regs->cs << 4;
     else
-        inst_addr = regs->eip;
+        inst_addr = hvm_get_segment_base(current, seg_cs);
+    inst_addr += regs->eip;
 
     memset(inst, 0, MAX_INST_LEN);
     if ( inst_copy_from_guest(inst, inst_addr, inst_len) != inst_len ) {
index 411a05634926ee68082c14b2acc8462c1a126a3a..455bdac52e3f336d6ce01ddf1106596d02c78fce 100644 (file)
@@ -510,6 +510,24 @@ unsigned long svm_get_ctrl_reg(struct vcpu *v, unsigned int num)
     return 0;                   /* dummy */
 }
 
+static unsigned long svm_get_segment_base(struct vcpu *v, enum segment seg)
+{
+    switch ( seg )
+    {
+    case seg_cs: return v->arch.hvm_svm.vmcb->cs.base;
+    case seg_ds: return v->arch.hvm_svm.vmcb->ds.base;
+    case seg_es: return v->arch.hvm_svm.vmcb->es.base;
+    case seg_fs: return v->arch.hvm_svm.vmcb->fs.base;
+    case seg_gs: return v->arch.hvm_svm.vmcb->gs.base;
+    case seg_ss: return v->arch.hvm_svm.vmcb->ss.base;
+    case seg_tr: return v->arch.hvm_svm.vmcb->tr.base;
+    case seg_gdtr: return v->arch.hvm_svm.vmcb->gdtr.base;
+    case seg_idtr: return v->arch.hvm_svm.vmcb->idtr.base;
+    case seg_ldtr: return v->arch.hvm_svm.vmcb->ldtr.base;
+    }
+    BUG();
+    return 0;
+}
 
 /* Make sure that xen intercepts any FP accesses from current */
 static void svm_stts(struct vcpu *v) 
@@ -821,6 +839,7 @@ int start_svm(void)
     hvm_funcs.pae_enabled = svm_pae_enabled;
     hvm_funcs.guest_x86_mode = svm_guest_x86_mode;
     hvm_funcs.get_guest_ctrl_reg = svm_get_ctrl_reg;
+    hvm_funcs.get_segment_base = svm_get_segment_base;
 
     hvm_funcs.update_host_cr3 = svm_update_host_cr3;
     
index 469c3a28b9d2b89b6371ba58604b5442686e7c1e..a166d4aa8c0bce9fea32af90a3237bc85b458f55 100644 (file)
@@ -501,6 +501,28 @@ static unsigned long vmx_get_ctrl_reg(struct vcpu *v, unsigned int num)
     return 0;                   /* dummy */
 }
 
+static unsigned long vmx_get_segment_base(struct vcpu *v, enum segment seg)
+{
+    unsigned long base;
+
+    BUG_ON(v != current);
+    switch ( seg )
+    {
+    case seg_cs: __vmread(GUEST_CS_BASE, &base); break;
+    case seg_ds: __vmread(GUEST_DS_BASE, &base); break;
+    case seg_es: __vmread(GUEST_ES_BASE, &base); break;
+    case seg_fs: __vmread(GUEST_FS_BASE, &base); break;
+    case seg_gs: __vmread(GUEST_GS_BASE, &base); break;
+    case seg_ss: __vmread(GUEST_SS_BASE, &base); break;
+    case seg_tr: __vmread(GUEST_TR_BASE, &base); break;
+    case seg_gdtr: __vmread(GUEST_GDTR_BASE, &base); break;
+    case seg_idtr: __vmread(GUEST_IDTR_BASE, &base); break;
+    case seg_ldtr: __vmread(GUEST_LDTR_BASE, &base); break;
+    default: BUG(); base = 0; break;
+    }
+    return base;
+}
+
 /* Make sure that xen intercepts any FP accesses from current */
 static void vmx_stts(struct vcpu *v)
 {
@@ -619,6 +641,7 @@ static void vmx_setup_hvm_funcs(void)
     hvm_funcs.pae_enabled = vmx_pae_enabled;
     hvm_funcs.guest_x86_mode = vmx_guest_x86_mode;
     hvm_funcs.get_guest_ctrl_reg = vmx_get_ctrl_reg;
+    hvm_funcs.get_segment_base = vmx_get_segment_base;
 
     hvm_funcs.update_host_cr3 = vmx_update_host_cr3;
 
index 2981df13dbd3e9bbb2956f5c5a7c46fe4369a855..c22258460c98d7c82a56a2e93340f4e49674b51c 100644 (file)
 #ifndef __ASM_X86_HVM_HVM_H__
 #define __ASM_X86_HVM_HVM_H__
 
+enum segment {
+    seg_cs,
+    seg_ss,
+    seg_ds,
+    seg_es,
+    seg_fs,
+    seg_gs,
+    seg_tr,
+    seg_ldtr,
+    seg_gdtr,
+    seg_idtr
+};
+
 /*
  * The hardware virtual machine (HVM) interface abstracts away from the
  * x86/x86_64 CPU virtualization assist specifics. Currently this interface
@@ -52,6 +65,7 @@ struct hvm_function_table {
      * 1) determine whether the guest is in real or vm8086 mode,
      * 2) determine whether paging is enabled,
      * 3) return the current guest control-register value
+     * 4) return the current guest segment descriptor base
      */
     int (*realmode)(struct vcpu *v);
     int (*paging_enabled)(struct vcpu *v);
@@ -59,6 +73,7 @@ struct hvm_function_table {
     int (*pae_enabled)(struct vcpu *v);
     int (*guest_x86_mode)(struct vcpu *v);
     unsigned long (*get_guest_ctrl_reg)(struct vcpu *v, unsigned int num);
+    unsigned long (*get_segment_base)(struct vcpu *v, enum segment seg);
 
     /* 
      * Re-set the value of CR3 that Xen runs on when handling VM exits
@@ -161,6 +176,12 @@ hvm_get_guest_ctrl_reg(struct vcpu *v, unsigned int num)
     return 0;                   /* force to fail */
 }
 
+static inline unsigned long
+hvm_get_segment_base(struct vcpu *v, enum segment seg)
+{
+    return hvm_funcs.get_segment_base(v, seg);
+}
+
 void hvm_stts(struct vcpu *v);
 void hvm_set_guest_time(struct vcpu *v, u64 gtime);
 void hvm_freeze_time(struct vcpu *v);